(function ( exports ) {

    //region ExecuteWorkflow

    /**
     * ExecuteWorkflow message
     * @param {string} workflowId Workflow unique identifier (GUID)
     * @param {string} entityId Entity unique identifier (GUID)
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {string} workflowId Workflow unique identifier (GUID)
     * @prop {string} entityId Entity unique identifier (GUID)
     * @prop {string} requestId Request unique identifier (GUID)
     * @memberOf COSA.Request 
     * @constructor ExecuteWorkflow
     */
    function ExecuteWorkflow ( workflowId, entityId, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.workflowId = workflowId;
        this.entityId = entityId;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, ExecuteWorkflow, {
        requestName: COSA.Const.Message.ExecuteWorkflow,
        retrieveParameters:function () {
            this.parameters = {
                'EntityId': new COSA.XrmGuid(this.entityId),
                'WorkflowId': new COSA.XrmGuid(this.workflowId)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.ExecuteWorkflow();
        }
    });

    //endregion ExecuteWorkflow

    //region Assign

    /**
     * Assign message
     * @param {COSA.EntityReference} target Target
     * @param {COSA.EntityReference} assignee Assignee
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {COSA.EntityReference} target Target
     * @prop {COSA.EntityReference} assignee Assignee
     * @memberOf COSA.Request
     * @constructor Assign
     */
    function Assign ( target, assignee, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.target = target;
        this.assignee = assignee;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, Assign, {
        requestName:COSA.Const.Message.Assign,
        retrieveParameters:function () {
            this.parameters = {
                'Target': this.target,
                'Assignee': this.assignee
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.Assign();
        }
    });

    //endregion Assign

    //region SetState

    /**
     * SetState message
     * @param {COSA.EntityReference} entityMoniker Entity Moniker
     * @param {number} state State
     * @param {number} status Status
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {COSA.EntityReference} entityMoniker Entity Moniker
     * @prop {number} state State
     * @prop {number} status Status
     * @memberOf COSA.Request
     * @constructor SetState
     */
    function SetState ( entityMoniker, state, status, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.entityMoniker = entityMoniker;
        this.state = state;
        this.status = status;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, SetState, {
        requestName:COSA.Const.Message.SetState,
        retrieveParameters:function () {
            this.parameters = {
                'EntityMoniker': this.entityMoniker,
                'State': new COSA.OptionSetValue(this.state),
                'Status': new COSA.OptionSetValue(this.status)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.SetState();
        }
    });

    //endregion SetState

    //region RetrieveUserPrivileges

    /**
     * RetrieveUserPrivileges message
     * @param {string} userId User unique identifier (GUID)
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {string} userId User unique identifier (GUID)
     * @memberOf COSA.Request
     * @constructor RetrieveUserPrivileges
     */
    function RetrieveUserPrivileges ( userId, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);
        this.userId = userId;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, RetrieveUserPrivileges, {
        requestName:COSA.Const.Message.RetrieveUserPrivileges,
        retrieveParameters:function () {
            this.parameters = {
                'UserId': new COSA.XrmGuid(this.userId)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.RetrieveUserPrivileges();
        }
    });

    //endregion RetrieveUserPrivileges

    //region RetrievePrincipalAccess

    /**
     * RetrievePrincipalAccess message
     * @param {COSA.EntityReference} principal Principal
     * @param {COSA.EntityReference} target Target
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {COSA.EntityReference} principal Principal
     * @prop {COSA.EntityReference} target Target
     * @memberOf COSA.Request
     * @constructor RetrievePrincipalAccess
     */
    function RetrievePrincipalAccess ( principal, target, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.principal = principal;
        this.target = target;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, RetrievePrincipalAccess, {
        requestName:COSA.Const.Message.RetrievePrincipalAccess,
        retrieveParameters:function () {
            this.parameters = {
                'Principal': this.principal,
                'Target': this.target
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.RetrievePrincipalAccess();
        }
    });

    //endregion RetrievePrincipalAccess

    //region LoseOpportunity

    /**
     * LoseOpportunity message
     * @param {COSA.BusinessEntity} opportunityClose Opportunity Close Entity
     * @param {COSA.OptionSetValue} status Status
     * @param {string} requestId Request Unique Identifier
     * @prop {COSA.BusinessEntity} opportunityClose Opportunity Close Entity
     * @prop {COSA.OptionSetValue} status Status
     * @memberOf COSA.Request
     * @constructor LoseOpportunity
     */
    function LoseOpportunity ( opportunityClose, status, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.opportunityClose = opportunityClose;
        this.status = status;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, LoseOpportunity, {
        requestName:COSA.Const.Message.LoseOpportunity,
        retrieveParameters:function () {
            this.parameters = {
                'OpportunityClose': this.opportunityClose,
                'Status': new COSA.OptionSetValue(this.status)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.LoseOpportunity();
        }
    });

    //endregion LoseOpportunity

    //region WinOpportunity

    /**
     * WinOpportunity message
     * @param {COSA.BusinessEntity} opportunityClose Opportunity Close Entity
     * @param {number} status Opportunity Status
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {COSA.BusinessEntity} opportunityClose Opportunity Close Entity
     * @prop {number} status Opportunity Status
     * @memberOf COSA.Request
     * @constructor WinOpportunity
     */
    function WinOpportunity ( opportunityClose, status, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.opportunityClose = opportunityClose;
        this.status = status;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, WinOpportunity, {
        requestName:COSA.Const.Message.WinOpportunity,
        retrieveParameters:function () {
            this.parameters = {
                'OpportunityClose': this.opportunityClose,
                'Status': new COSA.OptionSetValue(this.status)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.WinOpportunity();
        }
    });

    //endregion WinOpportunity

    //region QualifyLead

    /**
     * QualifyLead message
     * @param {COSA.EntityReference} lead Lead
     * @param {boolean} createAccount Create Account
     * @param {boolean} createContact Create Contact
     * @param {boolean} createOpportunity Create Opportunity
     * @param {number} status Lead Status
     * @param {string} requestId Request Unique Identifier (GUID)
     * @prop {COSA.EntityReference} lead Lead
     * @prop {boolean} createAccount Create Account
     * @prop {boolean} createContact Create Contact
     * @prop {boolean} createOpportunity Create Opportunity
     * @prop {number} status Lead Status
     * @prop {string} sourceCampaignId Source Campaign unique identifier (GUID)
     * @prop {string} opportunityCurrencyId Opportunity Currency unique identifier (GUID)
     * @prop {string} opportunityCustomerId Opportunity Customer unique identifier (GUID)
     * @memberOf COSA.Request
     * @constructor QualifyLead
     */
    function QualifyLead ( lead, createAccount, createContact, createOpportunity, status, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.lead = lead;
        this.createAccount = createAccount;
        this.createContact = createContact;
        this.createOpportunity = createOpportunity;
        this.status = status;
        this.sourceCampaignId = null;
        this.opportunityCurrencyId = null;
        this.opportunityCustomerId = null;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, QualifyLead, {
        requestName:COSA.Const.Message.QualifyLead,
        retrieveParameters:function () {
            this.parameters = {
                'LeadId': this.lead,
                'CreateContact': new COSA.XrmBoolean(this.createContact),
                'CreateAccount': new COSA.XrmBoolean(this.createAccount),
                'CreateOpportunity': new COSA.XrmBoolean(this.createOpportunity),
                'Status': new COSA.OptionSetValue(this.status)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.QualifyLead();
        }
    });

    //endregion QualifyLead

    //region AddListMemberList

    /**
     * AddListMembersList message
     * @param {string} listId List unique identifier (GUID)
     * @param {Array<string>} memberIds Members unique identifiers (GUID)
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {string} listId List unique identifier (GUID)
     * @prop {Array<string>} memberIds Members unique identifiers (GUID)
     * @memberOf COSA.Request
     * @constructor AddListMembersList
     */
    function AddListMembersList ( listId, memberIds, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.listId = listId;
        this.memberIds = memberIds;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, AddListMembersList, {
        requestName:COSA.Const.Message.AddListMembersList,
        retrieveParameters:function () {
            this.parameters = {
                'ListId': new COSA.XrmGuid(this.listId),
                'MemberIds': new COSA.ArrayOfGuid(this.memberIds)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.AddListMembersList();
        }
    });

    //endregion AddListMemberList

    //region AddMemberList

    /**
     * AddMemberList message
     * @param {string} listId List unique identifier (GUID)
     * @param {string} entityId Entity unique identifier (GUID)
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {string} listId List unique identifier (GUID)
     * @prop {string} entityId Entity unique identifier (GUID)
     * @memberOf COSA.Request
     * @constructor AddMemberList
     */
    function AddMemberList ( listId, entityId, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.listId = listId;
        this.entityId = entityId;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, AddMemberList, {
        requestName:COSA.Const.Message.AddMemberList,
        retrieveParameters:function () {
            this.parameters = {
                'ListId': new COSA.XrmGuid(this.listId),
                'EntityId': new COSA.XrmGuid(this.entityId)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.AddMemberList();
        }
    });

    //endregion AddMemberList

    //region CopyMembersList

    /**
     * CopyMembersList message
     * @param {string} sourceListId Source List unique identifier (GUID)
     * @param {string} targetListId Target List unique identifier (GUID)
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {string} sourceListId Source List unique identifier (GUID)
     * @prop {string} targetListId Target List unique identifier (GUID)
     * @memberOf COSA.Request
     * @constructor CopyMembersList
     */
    function CopyMembersList ( sourceListId, targetListId, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.sourceListId = sourceListId;
        this.targetListId = targetListId;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, CopyMembersList, {
        requestName:COSA.Const.Message.CopyMembersList,
        retrieveParameters:function () {
            this.parameters = {
                'SourceListId': new COSA.XrmGuid(this.sourceListId),
                'TargetListId': new COSA.XrmGuid(this.targetListId)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.CopyMembersList();
        }
    });

    //endregion CopyMembersList

    //region RemoveMemberList

    /**
     * RemoveMemberList message
     * @param {string} listId List unique identifier (GUID)
     * @param {string} entityId Entity unique identifier (GUID)
     * @param {string} requestId Request unique identifier (GUID)
     * @prop {string} entityId Entity unique identifier (GUID)
     * @prop {string} requestId Request unique identifier (GUID)
     * @memberOf COSA.Request
     * @constructor RemoveMemberList
     */
    function RemoveMemberList ( listId, entityId, requestId ) {
        COSA.Request.CrmRequest.call(this, requestId);

        this.listId = listId;
        this.entityId = entityId;
    }

    COSA.Util.deriveOverride(COSA.Request.CrmRequest, RemoveMemberList, {
        requestName:COSA.Const.Message.RemoveMemberList,
        retrieveParameters:function () {
            this.parameters = {
                'ListId': new COSA.XrmGuid(this.listId),
                'EntityId': new COSA.XrmGuid(this.entityId)
            };
        },
        getResponseInstance:function () {
            return new COSA.Response.RemoveMemberList();
        }
    });

    //endregion RemoveMemberList

    exports.ExecuteWorkflow = ExecuteWorkflow;
    exports.Assign = Assign;
    exports.SetState = SetState;
    exports.RetrieveUserPrivileges = RetrieveUserPrivileges;
    exports.RetrievePrincipalAccess = RetrievePrincipalAccess;
    exports.LoseOpportunity = LoseOpportunity;
    exports.WinOpportunity = WinOpportunity;
    exports.QualifyLead = QualifyLead;
    exports.AddListMembersList = AddListMembersList;
    exports.AddMemberList = AddMemberList;
    exports.CopyMembersList = CopyMembersList;
    exports.RemoveMemberList = RemoveMemberList;
})(COSA.Request);
